<?php
/**
 * quick_curd
 * ============================================================================
 * 版权所有 2024-2099 wltx666.com，并保留所有权利。
 * 网站地址: https://wltx666.com
 * ============================================================================
 * Author: 草上飞
 * Email: wltx@alipay168.cn
 * QQ: 2719875001
 * Date: 2024/12/15
 * 描述:
 */

namespace app\result;

use app\model\AppVersion;
use app\model\chat\ChatMessages;
use app\model\Feedback;
use app\model\goods\Goods;
use app\model\goods\GoodsCategory;
use app\model\UploadFilesLog;
use app\model\user\User;
use Qiniu\Auth;
use Qiniu\Storage\BucketManager;
use Qiniu\Storage\UploadManager;
use think\facade\Log;
use think\file\UploadedFile;

class UploadResult extends BaseResult
{
    public function __construct()
    {
        parent::__construct();
        $this->model = new UploadFilesLog();
    }

    public static function _getConfig()
    {
        $config = config('upload');
        $setConfig = (new SettingResult())->get_value('upload');
        if ($setConfig) {
            $config = array_merge($config, $setConfig);
        } else {
            return $config;
        }
        return $config;
    }

    //上传图片 todo 鉴黄
    public function image($args = [], $user_id = 0)
    {
        $to_table = trim($args['to_table'] ?? '');
        $file = request()->file('file');
        if (!$file) {
            return $this->error_return('请选择文件');
        }
        if (!$file->isValid()) {
            return $this->error_return('文件上传失败');
        }
        $ext = strtolower($file->extension());
        $config = self::_getConfig();
        if (!in_array($ext, $config['allow_ext'])) {
            return $this->error_return('文件类型不允许');
        }
        if ($file->getSize() > $config['allow_size']) {
            return $this->error_return('文件大小超出限制');
        }
        $logModel = new UploadFilesLog();
        $md5 = $file->md5();
        $has = $logModel->data_get(['md5' => $md5]);
        if ($has) {
            return $this->success_return('上传成功', [
                'url' => $has['path'],
                'full_url' => $has['full_url'],
                'name' => $has['name'],
                'size' => UploadFilesLogResult::format_size($has['size']),
                'md5' => $md5,
            ]);
        }
        $type = $config['type'];
        $filePart = 'images';
        if ($type == 'local') {
            $toDir = $config['storage'] . '/' . $filePart . '/';
            if (!is_dir($toDir)) {
                @mkdir($toDir, 0777, true);
            }
            if (!is_writable($toDir)) {
                return $this->error_return($config['upload_url'] . '上传目录没有写入权限');
            }
            $fileName = $file->md5() . '.' . $ext;
            $logData = [
                'name' => $file->getOriginalName(),
                'size' => $file->getSize(),
                'type' => $ext,
                'upload_type' => $type,
                'path' => $filePart . '/' . $fileName,
                'user_type' => $user_id ? 2 : 1,
                'user_id' => $user_id,
                'md5' => $md5,
                'to_table' => $to_table,
            ];
            try {
                $file->move($toDir, $fileName);
            } catch (\Exception $e) {
                return $this->error_return('上传失败:' . $e->getMessage());
            }
            if (!file_exists($toDir . $fileName)) {
                return $this->error_return('上传失败');
            }
            $localPath = $config['upload_url'] . '/' . $filePart . '/' . $fileName;
            $fullUrl = request()->domain() . $localPath;
            // 记录日志
            $logData['full_url'] = $fullUrl;
            $logData['path'] = $localPath;

            $logModel->save($logData);
            return $this->success_return('上传成功', [
                'url' => $localPath,
                'full_url' => $fullUrl,
                'name' => $logData['name'],
                'size' => UploadFilesLogResult::format_size($logData['size']),
                'md5' => $md5,
            ]);
        } elseif ($type == 'qiniu') {
            $qiniu = $this->local2qiniu($file->getPathname(), $md5 . '.' . $ext);
            if ($qiniu['code'] !== 0) {
                return $this->error_return($qiniu['msg']);
            }
            $qiniuData = $qiniu['data'];
            $logData = [
                'name' => $file->getOriginalName(),
                'size' => $file->getSize(),
                'type' => $ext,
                'upload_type' => $type,
                'path' => $qiniuData['path'],
                'user_type' => $user_id ? 2 : 1,
                'user_id' => $user_id,
                'md5' => $md5,
                'to_table' => $to_table,
            ];
            $localPath = $qiniuData['path'];
            $fullUrl = $qiniuData['full_url'];
            // 记录日志
            $logData['full_url'] = $fullUrl;
            $logModel->save($logData);
            return $this->success_return('上传成功', [
                'url' => $localPath,
                'full_url' => $fullUrl,
                'name' => $logData['name'],
                'size' => UploadFilesLogResult::format_size($logData['size']),
                'md5' => $md5,
            ]);
        } else {
            return $this->error_return('暂不支持该类型');
        }
    }

    // 获取文件扩展名
    function getFileExtensionFromUpload($fileInfo)
    {
        // 获取文件的MIME类型和后缀名
        $mimeType = strtolower($fileInfo['type']);
        $originalName = $fileInfo['name'];
        $extension = pathinfo($originalName, PATHINFO_EXTENSION);
        $extension = strtolower($extension);

        // 根据MIME类型调整扩展名
        if (str_contains($mimeType, 'jpeg') || str_contains($mimeType, 'jpg')) {
            $extension = 'jpg';
        } elseif (str_contains($mimeType, 'png')) {
            $extension = 'png';
        } elseif (str_contains($mimeType, 'msword')) {
            $extension = 'doc';
        } elseif (str_contains($mimeType, 'vnd.openxmlformats-officedocument.wordprocessingml.document')) {
            $extension = 'docx';
        } elseif (str_contains($mimeType, 'vnd.ms-excel')) {
            $extension = 'xls';
        } elseif (str_contains($mimeType, 'vnd.openxmlformats-officedocument.spreadsheetml.sheet')) {
            $extension = 'xlsx';
        } elseif (str_contains($mimeType, 'vnd.ms-powerpoint')) {
            $extension = 'ppt';
        } elseif (str_contains($mimeType, 'vnd.openxmlformats-officedocument.presentationml.presentation')) {
            $extension = 'pptx';
        } elseif ($mimeType == 'application/pdf') {
            $extension = 'pdf';
        } elseif (in_array($extension, ['txt'])) {
            // 对于文本文件直接确认
        } elseif (str_contains($mimeType, 'zip')) {
            $extension = 'zip';
        } elseif (str_contains($mimeType, 'x-rar-compressed')) {
            $extension = 'rar';
        } elseif (str_contains($mimeType, 'audio') || in_array($extension, ['mp3', 'wav', 'wma'])) {
            // 音频文件，保持原扩展名
        } elseif (str_contains($mimeType, 'video') || in_array($extension, ['mp4', 'avi', 'rmvb', 'flv', 'mkv', 'mov', 'rm', '3gp'])) {
            // 视频文件，保持原扩展名
        }

        return $extension;
    }

    public function file($args = [], $user_id = 0)
    {
        $to_table = trim($args['to_table'] ?? '');
        $file = request()->file('file');
        if (!$file) {
            return $this->error_return('请选择文件');
        }
        if (!$file->isValid()) {
            return $this->error_return('文件上传失败');
        }
        $ext = strtolower($file->extension());
        if (!$ext) {
            //通过$_FILES['file']获取
            //return $this->error_return('文件类型不允许', $_FILES['file']);
            $ext = $this->getFileExtensionFromUpload($_FILES['file']);
        }
        $config = self::_getConfig();
        //$config = config('upload');
        if (!in_array($ext, $config['allow_ext'])) {
            return $this->error_return('文件类型不允许', $ext);
        }
        if ($file->getSize() > $config['allow_size']) {
            return $this->error_return('文件大小超出限制');
        }
        $logModel = new UploadFilesLog();
        $md5 = $file->md5();
        $has = $logModel->data_get(['md5' => $md5]);
        if ($has) {
            return $this->success_return('上传成功', [
                'url' => $has['path'],
                'full_url' => $has['full_url'],
                'name' => $has['name'],
                'size' => UploadFilesLogResult::format_size($has['size']),
                'md5' => $md5,
            ]);
        }
        $type = $config['type'];
        $name = $file->getOriginalName();
        if (!empty($args['name'])) {
            $name = $args['name'];
        }
        $filePart = 'images';
        if ($type == 'local') {
            $toDir = $config['storage'] . '/' . $filePart . '/';
            if (!is_dir($toDir)) {
                @mkdir($toDir, 0777, true);
            }
            if (!is_writable($toDir)) {
                return $this->error_return($config['upload_url'] . '上传目录没有写入权限');
            }
            $fileName = $file->md5() . '.' . $ext;
            $logData = [
                'name' => $name,
                'size' => $file->getSize(),
                'type' => $ext,
                'upload_type' => $type,
                'path' => $filePart . '/' . $fileName,
                'user_type' => $user_id ? 2 : 1,
                'user_id' => $user_id,
                'md5' => $file->md5(),
                'to_table' => $to_table
            ];
            try {
                $file->move($toDir, $fileName);
            } catch (\Exception $e) {
                return $this->error_return('上传失败:' . $e->getMessage());
            }
            if (!file_exists($toDir . $fileName)) {
                return $this->error_return('上传失败');
            }
            $localPath = $config['upload_url'] . '/' . $filePart . '/' . $fileName;
            $fullUrl = request()->domain() . $localPath;
            // 记录日志
            $logData['full_url'] = $fullUrl;
            $logData['path'] = $localPath;

            $logModel->save($logData);
            return $this->success_return('上传成功', [
                'url' => $localPath,
                'full_url' => $fullUrl,
                'name' => $logData['name'],
                'size' => UploadFilesLogResult::format_size($logData['size']),
                'md5' => $md5,
            ]);
        } elseif ($type == 'qiniu') {
            $qiniu = $this->local2qiniu($file->getPathname(), $md5 . '.' . $ext);
            if ($qiniu['code'] !== 0) {
                return $this->error_return($qiniu['msg']);
            }
            $qiniuData = $qiniu['data'];
            $logData = [
                'name' => $name,
                'size' => $file->getSize(),
                'type' => $ext,
                'upload_type' => $type,
                'path' => $qiniuData['path'],
                'user_type' => $user_id ? 2 : 1,
                'user_id' => $user_id,
                'md5' => $md5,
                'to_table' => $to_table,
            ];
            $localPath = $qiniuData['path'];
            $fullUrl = $qiniuData['full_url'];
            // 记录日志
            $logData['full_url'] = $fullUrl;
            $logModel->save($logData);
            return $this->success_return('上传成功', [
                'url' => $localPath,
                'full_url' => $fullUrl,
                'name' => $logData['name'],
                'size' => UploadFilesLogResult::format_size($logData['size']),
                'md5' => $md5,
            ]);
        } else {
            return $this->error_return('暂不支持该类型');
        }
    }

    public function chunk($args = [])
    {
        $to_table = trim($args['to_table'] ?? '');
        $file = request()->file('file');
        if (!$file) {
            return $this->error_return('请选择文件');
        }
        if (!$file->isValid()) {
            return $this->error_return('文件上传失败');
        }

        $fileName = request()->post('filename');
        $fileNameArr = explode(".", $fileName, 2);

        $ext = strtolower($file->extension());
        $config = self::_getConfig();
        if (!empty($ext) && !in_array($ext ?: $fileNameArr[1] ?? '', $config['chunk_allow_ext'])) {
            Log::record("文件类型不允许：" . $ext);
            return $this->error_return('文件类型不允许');
        }
        if ($file->getSize() > $config['chunk_allow_size']) {
            return $this->error_return('文件大小超出限制');
        }

        $postData = request()->post();


        if (!isset($postData['chunkNumber'], $postData['totalChunks'], $postData['filename'])) {
            return $this->error_return('上传失败');
        }

        $chunkNumber = request()->post('chunkNumber');
        $totalChunks = request()->post('totalChunks');

        $chunkFileName = $fileNameArr[0] . "_" . $chunkNumber . '.part';
        $filePart = 'chunk/chunk';
        $chunkToDir = $config['storage'] . '/' . $filePart . '/';
        if (!is_dir($chunkToDir)) {
            @mkdir($chunkToDir, 0777, true);
        }
        if (!is_writable($chunkToDir)) {
            return $this->error_return($config['upload_url'] . '上传目录没有写入权限');
        }

        //清理旧分片，避免分片数量过多，占用空间过大，半小时以前的
        $chunkFiles = glob($chunkToDir . $fileNameArr[0] . "_*.part");
        $time = time();
        foreach ($chunkFiles as $chunkFile) {
            $fileTime = filemtime($chunkFile);
            if ($fileTime < $time - 1800) {
                unlink($chunkFile);
            }
        }

        $partFileName = $chunkToDir . $fileNameArr[0] . "_" . $chunkNumber . '.part';
        if (!file_exists($partFileName)) {
            try {
                $file->move($chunkToDir, $chunkFileName);
            } catch (\Exception $e) {
                return $this->error_return('上传失败:' . $e->getMessage());
            }
            if (!file_exists($chunkToDir . $chunkFileName)) {
                return $this->error_return('上传失败');
            }
        }

        // 判断分片是否都完整，完整则合并
        $finishStatus = true;
        for ($i = 1; $i <= $totalChunks; $i++) {
            $partFileName = $chunkToDir . $fileNameArr[0] . "_" . $i . '.part';
            if (!file_exists($partFileName)) {
                $finishStatus = false;
            }
        }

        if ($finishStatus) {

            $toDir = $config['storage'] . '/files/';
            if (!is_dir($toDir)) {
                @mkdir($toDir, 0777, true);
            }
            if (!is_writable($toDir)) {
                return $this->error_return($config['upload_url'] . '上传目录没有写入权限');
            }

            $fullFileName = $toDir . $fileName;

            if (!file_exists($fullFileName)) {
                $fp = fopen($fullFileName, 'ab');

                for ($i = 1; $i <= $totalChunks; $i++) {
                    $partFileName = $chunkToDir . $fileNameArr[0] . "_" . $i . '.part';
                    $partFile = fopen($partFileName, 'rb');
                    fwrite($fp, fread($partFile, filesize($partFileName)));
                    fclose($partFile);
                    @unlink($partFileName);
                }
                fclose($fp);
            } else {
                for ($i = 1; $i <= $totalChunks; $i++) {
                    @unlink($partFileName);
                }
            }

            if (!file_exists($fullFileName)) {
                return $this->error_return('上传失败');
            }

            $md5 = md5_file($fullFileName);
            $logModel = new UploadFilesLog();
            $has = $logModel->data_get(['md5' => $md5]);
            if ($has) {
                @unlink($fullFileName);
                return $this->success_return('上传成功', [
                    'url' => $has['path'],
                    'full_url' => $has['full_url'],
                    'name' => $has['name'],
                    'size' => UploadFilesLogResult::format_size($has['size']),
                    'md5' => $md5,
                ]);
            }
            $fullMd5Filename = $toDir . $md5 . '.' . $fileNameArr[1];
            // 重命名
            if (!rename($fullFileName, $fullMd5Filename)) {
                return $this->error_return('上传失败');
            }
            $ext = strtolower(pathinfo($fullMd5Filename, PATHINFO_EXTENSION));
            $type = $config['type'];

            if ($type == 'local') {
                $logData = [
                    'name' => basename($fullFileName),
                    'size' => filesize($fullMd5Filename),
                    'type' => $ext,
                    'upload_type' => $type,
                    'path' => '/files/' . basename($fullMd5Filename),
                    'user_type' => 1,
                    'md5' => $md5,
                    'to_table' => $to_table,

                ];
                $localPath = $config['upload_url'] . $logData['path'];
                $fullUrl = request()->domain() . $localPath;
                // 记录日志
                $logData['full_url'] = $fullUrl;
                $logData['path'] = $localPath;
                $logModel->save($logData);
            } elseif ($type == 'qiniu') {
                $qiniu = $this->local2qiniu($fullMd5Filename, $md5 . '.' . $ext);
                if ($qiniu['code'] !== 0) {
                    return $this->error_return($qiniu['msg']);
                }
                $qiniuData = $qiniu['data'];
                $logData = [
                    'name' => basename($fullFileName),
                    'size' => filesize($fullMd5Filename),
                    'type' => $ext,
                    'upload_type' => $type,
                    'path' => $qiniuData['path'],
                    'user_type' => 1,
                    'md5' => $md5,
                    'to_table' => $to_table,
                ];
                $localPath = $qiniuData['path'];
                $fullUrl = $qiniuData['full_url'];
                // 记录日志
                $logData['full_url'] = $fullUrl;
                $logModel->save($logData);
            }


            return $this->success_return('上传成功', [
                'url' => $localPath,
                'full_url' => $fullUrl,
                'name' => $logData['name'],
                'size' => UploadFilesLogResult::format_size($logData['size']),
                'md5' => $md5,
            ]);

        }

        return $this->success_return('上传成功');
    }

    public function get($args = [])
    {
        $id = intval($args['id'] ?? 0);
        $data = $this->model->data_get(['id' => $id]);
        return $this->success_return('success', $data);
    }

    public function list_group()
    {
        return self::success_return();
    }

    public function list($args = [])
    {
        $page = intval($args['page'] ?? 1);
        $page_size = intval($args['page_size'] ?? 17);
        $keyword = $args['keyword'] ?? '';
        $all = intval($args['all'] ?? 0);
        if ($all) {
            $page_size = intval($args['limit'] ?? 10);
        }
        $user_type = intval($args['user_type'] ?? 0);
        $sort = $args['sort'] ?? '';
        $model = (new UploadFilesLog());
        $where = [];
        if ($keyword) {
            $where[] = ['name|user_id', 'like', '%' . $keyword . '%'];
        }
        if (!$all) {
            $where[] = ['user_type', '=', 1];//只查询后台上传
        }
        if ($user_type) {
            $where[] = ['user_type', '=', $user_type];
        }
        $order = 'id desc';
        if ($sort) {
            $order = $sort;
        }
        $field = '*';
        $total = $model->data_count($where);
        $data = $model->data_list($where, $field, $order, $page, $page_size);
        if ($data) {
            $allUser = (new User())->data_list_nopage([['user_id', 'in', array_column($data->toArray(), 'user_id')]], 'user_id,account');
            if ($allUser) {
                $userMap = array_column($allUser, 'account', 'user_id');
            }

            foreach ($data as &$v) {
                $v['file_type'] = self::get_file_type($v['type'], $v['full_url']);
                $v['preview_url'] = self::get_file_preview_url($v['file_type'], $v);
                $v['size'] = UploadFilesLogResult::format_size($v['size']);
                $v['enable_del'] = false;
                if ($all) {
                    $v['enable_del'] = $this->check_enable_delete($v)['code'] === 0;
                }
                $v['user_account'] = $userMap[$v['user_id']] ?? $v['user_id'];
                $v['upload_type_desc'] = UploadFilesLogResult::get_upload_type_desc($v['upload_type']);
            }
            unset($v);
        }
        return self::success_return('success', [
            'total' => $total,
            'list' => $data,
        ]);
    }

    public static function get_file_preview_url($type, $v)
    {
        $url = request()->domain() . '/static/image/file_icon/files.png';
        switch ($type) {
            case 'image':
                $url = $v['full_url'];
                break;
            case 'video':
                $url = request()->domain() . '/static/image/file_icon/video.png';
                break;
            case 'zip':
                $url = request()->domain() . '/static/image/file_icon/zip.png';
                break;
            case 'apk':
                $url = request()->domain() . '/static/image/file_icon/apk.png';
                break;
            case 'doc':
                $url = request()->domain() . '/static/image/file_icon/doc.png';
                break;
            default:

                break;
        }
        return $url;
    }

    private static function get_file_type($type, $url)
    {
        if (empty($type)) {
            $type = strtolower(pathinfo($url, PATHINFO_EXTENSION));
        }
        if (in_array($type, ['jpg', 'jpeg', 'png', 'gif', 'bmp'])) {
            return 'image';//图片
        }
        if (in_array($type, ['mp4', 'avi', 'wmv', 'rmvb'])) {
            return 'video';//视频
        }
        if (in_array($type, ['mp3', 'wav', 'wma'])) {
            return 'audio';//音频
        }
        if (in_array($type, ['zip', 'rar', '7z'])) {
            return 'zip';//压缩包
        }
        if (in_array($type, ['apk', 'wgt'])) {
            return 'apk';
        }
        if (in_array($type, ['doc', 'docx', 'xls', 'xlsx', 'pdf'])) {
            return 'doc';
        }

        return 'file';
    }


    private function check_enable_delete($data)
    {
        $url = $data['full_url'];
        $to_table = $data['to_table'] ?? '';
        $type = self::get_file_type($data['type'], $url);
        if ($type == 'image' && (new GoodsCategory())->data_get([['image', 'like', '%' . $url . '%']])) {
            return self::error_return('文件有关联商品分类数据，无法删除');
        }
        if ($type == 'image' && (new Goods())->data_get([['goods_image', 'like', '%' . $url . '%']])) {
            return self::error_return('文件有关联商品分类数据，无法删除');
        }
        if (in_array($type, ['zip', 'apk', 'wgt']) && (new AppVersion())->data_get(['url' => $url])) {
            return self::error_return('文件有关联版本数据，无法删除');
        }

        if ($type == 'image' && (new User())->data_get(['avatar' => $url])) {
            return self::error_return('文件有关联头像数据，无法删除');
        }
        if ($type == 'image' && (new Feedback())->data_get([['images', 'like', '%' . $url . '%']])) {
            return self::error_return('文件有关联反馈数据，无法删除');
        }
        if (!in_array($data['upload_type'], ['local', 'qiniu'])) {
            return self::error_return('此文件上传类型不支持删除');
        }
        if ($to_table == 'chat_messages') {
            if ((new ChatMessages())->get_value(['content' => $url], 'id')) {
                return self::error_return('文件有关联聊天消息数据，无法删除');
            }
        }
        return self::success_return();
    }

    public function del_data($args)
    {
        $id = intval($args['id'] ?? 0);
        if (!$id) {
            return self::error_return('请选择记录');
        }
        $data = $this->model->data_get(['id' => $id]);
        if (!$data) {
            return self::error_return('记录不存在');
        }

        $check = $this->check_enable_delete($data);
        if ($check['code'] <> 0) {
            return $check;
        }
        if ($data['upload_type'] == 'qiniu') {
            $res = $this->del_qiniu($data);
            if ($res['code'] <> 0) {
                return $res;
            }
        } else {
            $file_path = public_path() . $data['path'];
            if (!file_exists($file_path)) {
                $this->model->data_del(['id' => $id]);
                return self::success_return('文件不存在, 已删除数据库记录');
            }
            if (!unlink($file_path)) {
                return self::error_return('删除失败');
            }
        }
        $this->model->data_del(['id' => $id]);
        bs_log($data, 'del_file', 'del_file.log');
        return self::success_return('删除成功');
    }

    private function del_qiniu($data)
    {
        $config = self::_getConfig()['qiniu'] ?? [];
        if (empty($config)) {
            return self::error_return('未配置七牛');
        }
        $key = $data['path'];
        $auth = new Auth($config['access_key'], $config['secret_key']);
        $bucket = $config['bucket'];
        $bucketMgr = new BucketManager($auth);
        try {
            [$success, $err] = $bucketMgr->delete($bucket, $key);
        } catch (\Exception $e) {
            return self::error_return('七牛删除失败：' . $e->getMessage());
        }
        if ($err) {
            return self::error_return('七牛删除失败:' . $err->message());
        }
        return self::success_return('删除成功');
    }

    public function local2qiniu($localFile, $toFileName)
    {
        $config = self::_getConfig()['qiniu'] ?? [];
        if (empty($config)) {
            return self::error_return('未配置七牛');
        }
        $auth = new Auth($config['access_key'], $config['secret_key']);
        $token = $auth->uploadToken($config['bucket']);
        $uploadMgr = new UploadManager();
        $path = $config['path'] ?? 'bs-sku-shop';
        $key = $path . '/' . $toFileName;
        $filePath = $localFile;
        try {
            [$ret, $err] = $uploadMgr->putFile($token, $key, $filePath);
        } catch (\Exception $e) {
            return self::error_return('七牛上传失败：' . $e->getMessage());
        }
        if (!$err) {
            return self::success_return('七牛上传成功', [
                'path' => $key,
                'full_url' => rtrim($config['domain'], '/') . '/' . ltrim($key, '/'),
            ]);
        } else {
            return self::error_return('七牛上传失败：' . $err->message());
        }
    }

    // 获取文件信息
    public static function get_file_info($url, $batch = false)
    {
        if (!$url) {
            return $url;
        }
        if ($batch && is_array($url)) {
            $logs = (new UploadFilesLog())->data_list_nopage([['full_url', 'in', $url]]);
        } else {
            $logs = (new UploadFilesLog())->data_list_nopage(['full_url' => $url]);
        }
        if (empty($logs)) {
            return $url;
        }

        $file_info = [];

        foreach ($logs as $log) {
            $getSize = function ($size) {
                $size = (int)$size;
                $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
                for ($i = 0; $size >= 1024 && $i < 5; $i++) {
                    $size /= 1024;
                }
                return round($size, 2) . $units[$i];
            };
            $file_info[] = [
                'name' => $log['name'],
                'size' => $getSize($log['size']),
                'type' => $log['type'],
                'url' => $log['full_url'],
                'md5' => $log['md5'],
            ];
        }

        return $batch ? $file_info : ($file_info[0] ?? $url);
    }
}
